/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * EcranImport.java
 *
 * Created on 7 avr. 2010, 17:08:32
 */

package vue;

import controleur.CCLogger;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Date;
import java.util.Vector;
import java.util.logging.Level;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.filechooser.*;
import main.Outils;
import modele.Image;

/**
 *
 * @author Synapse
 */
public class EcranImport extends Ecran {

    // Taille maxi des images avant importation
    private final long TAILLE_MAXI_IMPORT = (1024*1024 * 16);

    // Libellé dans le chooser
    private final String LIBELLE_CHOOSER = "Images JPG de moins de 12 Mo";

    // Taille maxi des images une fois importées
    private final long TAILLE_MAXI_APRES_IMPORT = (1024*1024 * 1);

    // Reduction maximum de taille
    private final double REDUCTION_MAXIMUM = 0.20;

    // Nombre d'image requise par le modèle
    private int nbImagesModele;

    // Explorateur de fichier
    private JFileChooser chooser;

    // Liste des images importées
    private Vector<Image> imagesList;

    /**
     * Constructeur de la classe EcranImport
     * @param mere FenetreMere
     * @see FenetreMere
     */
    public EcranImport(FenetreMere mere) {
        super(mere);
        
        initComponents();
        try
        {
            // Récupération du nombres d'images nécessaires pour le modèle choisi
            nbImagesModele = ressources.getCartePostale().getModele().getZoneImage().length;
            //nbImagesModele = 3;
            if( nbImagesModele == 1 ) labIndication.setText("Le modèle de carte sélectionné requière 1 photo :");
            else labIndication.setText("Le modèle de carte sélectionné requière " + nbImagesModele + " photos :");

            // Paramétrage du JFileChooser
            /*try{
                chooser = VueFileChooser.createFileChooser(new File("D:\\photos\\"));
            }
            catch(IOException ex){
                //chooser.showOpenDialog(null);
            }*/
            chooser = new JFileChooser();
            FileFilter imagesFilter = new FiltreImages();
            chooser.addChoosableFileFilter(imagesFilter); // Ajout du filtre personnalisé
            chooser.setAcceptAllFileFilterUsed(false); // On interdit le filtre "Tous les fichiers"
            chooser.setMultiSelectionEnabled(true); // On autorise la selection multiple ( TODO : éviter de passer par le bouton Ctrl)
            chooser.setCurrentDirectory(new File("/"));
            chooser.changeToParentDirectory();
            // Prévisualisation des images dans l'explorateur
            //getRoots();
            ImagePreviewPanel preview = new ImagePreviewPanel();
            chooser.setAccessory(preview);
            chooser.addPropertyChangeListener(preview);

            // Initialisation du vecteur contenant les url des images
            imagesList = ressources.getImagesImportees();

            // Pour initialisation
            rechargePanelPreview();
        }
        catch (Exception ex) {
            CCLogger.Write(Level.SEVERE, Outils.getStackTrace(ex));
            this.afficherMessageErreur("Une erreur est survenue lors de l'initialison de l'écran Import.");
        }
    }

    /*public static String[] getRoots() {
        File[] roots = File.listRoots();
        String[] names = new String[roots.length];
        for (int i = 0; i < roots.length; ++i){
            names[i] = roots[i].getPath();
        }
        return names;
    }*/

    /**
     * Getter pour les images importées
     * @return Vector<Image>
     */
    public Vector<Image> getImagesImportees(){
        return imagesList;
    }

    /**
     * Permet de recharger le panel qui accueil les images importées
     */
    private void rechargePanelPreview(){

        loader.setText("Chargement en cours...");
        panel.removeAll();
        GridLayout grillePositionnement = new GridLayout(imagesList.size(), 1);
        panel.setLayout( grillePositionnement );

        int i = 0;
        for (Image image : imagesList) {
            i++;
            JPanel subpanel = new JPanel();
            subpanel.setBounds(10, 10, 0, 0);

            ImageIcon img = new ImageIcon(image.getImageOuMiniature());
            subpanel.add(new JLabel(img));
            
            //Ajout du bouton de suppression dans la vue
            JButton btn = new JButton();
            btn.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    // Récupération du numéro inscrit dans le texte du label, à la suite de "Supprimer "
                    int nb = Integer.parseInt(((JButton)evt.getSource()).getText().substring(10));
                    // Suppression de l'image dans la liste
                    imagesList.removeElementAt(nb-1);
                    rechargePanelPreview();
                }
            });
            btn.setText("Supprimer "+i);
            btn.setSize(140, 35);
            JLabel modified = new JLabel("Dernière modification : " + image.getDateCliche());
            subpanel.add(btn);
            subpanel.add(modified);
            panel.add(subpanel);
        }
        panel.repaint(); // Utile pour la suppression de la dernière image de la liste
        scrollpane.validate();
        loader.setText("");


        // Si le nombre requit d'images ont été chargées, ont active le bouton suivant
        if( imagesList.size() == nbImagesModele ){
            btnSuivant.setEnabled(true);
            btnImporter.setEnabled(false);
        }
        else{
            btnSuivant.setEnabled(false);
            btnImporter.setEnabled(true);
        }

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        labBandeau = new javax.swing.JLabel();
        btnPrecedent = new javax.swing.JButton();
        btnRecommencer = new javax.swing.JButton();
        btnSuivant = new javax.swing.JButton();
        labIndication = new javax.swing.JLabel();
        btnImporter = new javax.swing.JButton();
        scrollpane = new javax.swing.JScrollPane();
        panel = new javax.swing.JPanel();
        loader = new javax.swing.JLabel();

        setBackground(new java.awt.Color(255, 255, 255));
        setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 204, 204), 2));
        setMaximumSize(new java.awt.Dimension(1024, 768));
        setMinimumSize(new java.awt.Dimension(1024, 768));
        setPreferredSize(new java.awt.Dimension(1024, 768));

        labBandeau.setIcon(new javax.swing.ImageIcon(getClass().getResource("/vue/images/choiximport.png"))); // NOI18N
        labBandeau.setMaximumSize(new java.awt.Dimension(1024, 88));
        labBandeau.setMinimumSize(new java.awt.Dimension(1024, 88));
        labBandeau.setPreferredSize(new java.awt.Dimension(1024, 88));

        btnPrecedent.setFont(new java.awt.Font("Tahoma", 0, 18));
        btnPrecedent.setText("< Précédent");
        btnPrecedent.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnPrecedentActionPerformed(evt);
            }
        });

        btnRecommencer.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        btnRecommencer.setText("Recommencer");
        btnRecommencer.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnRecommencerActionPerformed(evt);
            }
        });

        btnSuivant.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        btnSuivant.setText("Suivant >");
        btnSuivant.setEnabled(false);
        btnSuivant.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnSuivantActionPerformed(evt);
            }
        });

        labIndication.setFont(new java.awt.Font("Tahoma", 0, 18));
        labIndication.setText("Le modèle de carte sélectionné requière 4 photos:");

        btnImporter.setFont(new java.awt.Font("Tahoma", 0, 18));
        btnImporter.setText("Importer");
        btnImporter.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnImporterActionPerformed(evt);
            }
        });

        scrollpane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        scrollpane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollpane.setWheelScrollingEnabled(false);

        javax.swing.GroupLayout panelLayout = new javax.swing.GroupLayout(panel);
        panel.setLayout(panelLayout);
        panelLayout.setHorizontalGroup(
            panelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 728, Short.MAX_VALUE)
        );
        panelLayout.setVerticalGroup(
            panelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 479, Short.MAX_VALUE)
        );

        scrollpane.setViewportView(panel);

        loader.setFont(new java.awt.Font("Tahoma", 1, 18));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(labBandeau, javax.swing.GroupLayout.DEFAULT_SIZE, 2067, Short.MAX_VALUE)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(labIndication)
                            .addComponent(btnPrecedent, javax.swing.GroupLayout.PREFERRED_SIZE, 200, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addGap(1, 1, 1)
                                .addComponent(btnRecommencer, javax.swing.GroupLayout.PREFERRED_SIZE, 200, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 202, Short.MAX_VALUE)
                                .addComponent(btnSuivant, javax.swing.GroupLayout.PREFERRED_SIZE, 200, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addGroup(layout.createSequentialGroup()
                                .addGap(135, 135, 135)
                                .addComponent(loader)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 468, Short.MAX_VALUE))))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(57, 57, 57)
                        .addComponent(btnImporter, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGap(100, 100, 100)
                        .addComponent(scrollpane, javax.swing.GroupLayout.PREFERRED_SIZE, 751, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addGap(1058, 1058, 1058))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(labBandeau, javax.swing.GroupLayout.PREFERRED_SIZE, 94, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(18, 18, 18)
                        .addComponent(labIndication))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(30, 30, 30)
                        .addComponent(loader, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(btnImporter, javax.swing.GroupLayout.PREFERRED_SIZE, 47, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(scrollpane, javax.swing.GroupLayout.PREFERRED_SIZE, 498, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(60, 60, 60)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnPrecedent, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnRecommencer, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnSuivant, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    /**
     * Ecouteur pour le bouton "Précédent".
     * Indique au controleur que l'utilisateur souhaite revenir sur l'écran précédent
     * Pas de retour.
     * @param evt java.awt.event.ActionEvent
     */
    private void btnPrecedentActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPrecedentActionPerformed
        controleur.trImportPrecedent();
}//GEN-LAST:event_btnPrecedentActionPerformed

    /**
     * Ecouteur pour le bouton "Recommencer".
     * Indique que l'utilisateur souhaite recommencer
     * Pas de retour.
     * @param evt java.awt.event.ActionEvent
     */
    private void btnRecommencerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRecommencerActionPerformed
        this.trClicSurRecommencer();
}//GEN-LAST:event_btnRecommencerActionPerformed

     /**
     * Ecouteur pour le bouton "Suivant".
     * Indique au controleur que l'utilisateur souhaite revenir sur l'écran suivant
     * Pas de retour.
     * @param evt java.awt.event.ActionEvent
     */
    private void btnSuivantActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSuivantActionPerformed
        controleur.trImportSuivant();
}//GEN-LAST:event_btnSuivantActionPerformed

    /**
     * Ecouteur pour le bouton "Importer".
     * Indique que l'utilisateur souhaite importer des images.
     * Cette action ouvre un objet FileChooser.
     * Pas de retour.
     * @param evt java.awt.event.ActionEvent
     */
    private void btnImporterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnImporterActionPerformed

        if( imagesList.size() < nbImagesModele ){
            
            int res = chooser.showOpenDialog(null);

            String message = "L'importation peut prendre entre quelques\nsecondes et plusieurs minutes.\nProcéder à l'import ?";
            
            if(res == JFileChooser.APPROVE_OPTION && afficherMessageConfirmation(message) ){

                //des fichiers ont été choisis (sortie par OK)
                File[] fs = chooser.getSelectedFiles();
                for( int i = 0; i<fs.length; i++){
                    if ( imagesList.size() == nbImagesModele ){
                        afficherMessageErreur("Trop d'images ont été importées.\nLes dernières ne seront pas importées.");
                        break;
                    }
                    else{
                        // On met un curseur en sablier
                        setCursor( Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                        
                        // On importe concrètement l'image
                        try{
                            BufferedImage buf = ImageIO.read( fs[i] );
                            if ( isValidDimensions(ImageIO.read(fs[i]).getHeight(), ImageIO.read(fs[i]).getWidth()  ) ){

                                // Si besoin on la réduit pour gagner en taille
                                long tailleImage = fs[i].length();
                                if( tailleImage > TAILLE_MAXI_APRES_IMPORT ) {

                                    // On va redimmensionner au prorata des tailles de fichier
                                    double scaleValue = (double)TAILLE_MAXI_APRES_IMPORT / (double)tailleImage;

                                    // Ne pas trop dégrader l'image
                                    if( scaleValue < REDUCTION_MAXIMUM )
                                        scaleValue = REDUCTION_MAXIMUM;

    //                                System.out.println("Taille fichier : " + tailleImage);
    //                                System.out.println("Taille voulue : " + TAILLE_MAXI_APRES_IMPORT);
    //                                System.out.println("Reduction facteur : " + scaleValue);

                                    buf = Outils.homothetie(buf, scaleValue);
                                }
                                // Création classe Image
                                Image img = new Image(null, null, new Date(fs[i].lastModified()), buf);

                                // On met en mémoire pour gagner de la place
                                img.creerMiniature(new Dimension(280, 280));
                                img.enregistrerEnMemoire();

                                // On ajoute à la liste
                                imagesList.addElement(img);
                            }
                            else{
                                afficherMessageErreur("L'image possède des dimensions trop importantes. Elle n'est donc pas importée");
                            }

                        }catch(final java.lang.OutOfMemoryError ex){
                            afficherMessageErreur("L'image est trop grosse");
                            setCursor( Cursor.getDefaultCursor() );
                            ex.printStackTrace();
                        }
                        catch(Exception ex){
                            afficherMessageErreur("Problème lors de l'import d'image");
                            ex.printStackTrace();
                        }

                        // On remet un curseur standart
                        setCursor( Cursor.getDefaultCursor() );
                    }
                }
                rechargePanelPreview();
            }
           
        }
        else{
            afficherMessageErreur("Vous avez déjà importé assez d'images.");
        }
    }//GEN-LAST:event_btnImporterActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnImporter;
    private javax.swing.JButton btnPrecedent;
    private javax.swing.JButton btnRecommencer;
    private javax.swing.JButton btnSuivant;
    private javax.swing.JLabel labBandeau;
    private javax.swing.JLabel labIndication;
    private javax.swing.JLabel loader;
    private javax.swing.JPanel panel;
    private javax.swing.JScrollPane scrollpane;
    // End of variables declaration//GEN-END:variables

    private boolean isValidDimensions(int height, int width){
        boolean isValid = false;
        if( height <= 2048 && width <= 1536 ) isValid = true;
        else if( height <= 1536 && width <= 2048 ) isValid = true;
        return isValid;
    }

    /**
     * Class FiltreImage, héritée de FileFilter.
     * @see FileFilter
     */
    private class FiltreImages extends FileFilter{
       //Description et extension acceptée par le filtre
//       private String description;
//       private String extension;

       /**
        * Constructeur de la class FiltreImage
        * A partir de la description et de l'extension acceptée
        */
       public FiltreImages(){
//          if(description == null || extension ==null){
//             throw new NullPointerException("La description (ou extension) ne peut être null.");
//          }
//          this.description = description;
//          this.extension = extension;
       }

       /**
        * Implémentation de FileFilter
        * @param file type File
        * @return boolean
        * @see File
        */
       public boolean accept(File file){
          if(file.isDirectory()) {
             return true;
          }
          String nomFichier = file.getName().toLowerCase();
          boolean extensionOk = nomFichier.endsWith("jpg") || nomFichier.endsWith("jpeg");

          long tailleFichier = file.length();
          boolean tailleFichierOk = tailleFichier <= TAILLE_MAXI_IMPORT;

//          System.out.println("Fichier " + file.getName() + " => " + file.length() + " (max is " + TAILLE_MAXI_IMPORT + ")");

          return (extensionOk && tailleFichierOk);
       }

       /**
        * Getter implémenter pour Description
        * @return String
        */
        public String getDescription(){
            return LIBELLE_CHOOSER;
       }
    }

    /**
     * Class ImagePreviewPanel, hérité de JPanel
     * @see JPanel
     */
    public class ImagePreviewPanel extends JPanel
        implements PropertyChangeListener {

        private int width, height;
        private ImageIcon icon;
        private java.awt.Image image;
        private static final int ACCSIZE = 155;
        private Color bg;

        /**
         * Constructeur de la class ImagePreviewPanel
         */
        public ImagePreviewPanel() {
            setPreferredSize(new Dimension(ACCSIZE, -1));
            bg = getBackground();
        }

        /**
         * Permet de s'assurer que l'extension des fichiers corresponts avec ceux qu'il doit etre
         * @param e type PropertyChangeEvent
         */
        public void propertyChange(PropertyChangeEvent e) {
            String propertyName = e.getPropertyName();

            // Make sure we are responding to the right event.
            if (propertyName.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
                File selection = (File)e.getNewValue();
                String name;

                if (selection == null)
                    return;
                else
                    name = selection.getAbsolutePath();

                /*
                 * Make reasonably sure we have an image format that AWT can
                 * handle so we don't try to draw something silly.
                 */
                if ((name != null) &&
                        name.toLowerCase().endsWith(".jpg") ||
                        name.toLowerCase().endsWith(".jpeg") ||
                        name.toLowerCase().endsWith(".gif") ||
                        name.toLowerCase().endsWith(".png")) {
                    icon = new ImageIcon(name);
                    image = icon.getImage();
                    scaleImage();
                    repaint();
                }
            }
        }

        /**
         * Détermine l'échelle de l'image.
         */
        private void scaleImage() {
            width = image.getWidth(this);
            height = image.getHeight(this);
            double ratio = 1.0;

            /*
             * Determine how to scale the image. Since the accessory can expand
             * vertically make sure we don't go larger than 150 when scaling
             * vertically.
             */
            if (width >= height) {
                ratio = (double)(ACCSIZE-5) / width;
                width = ACCSIZE-5;
                height = (int)(height * ratio);
            }
            else {
                if (getHeight() > 150) {
                    ratio = (double)(ACCSIZE-5) / height;
                    height = ACCSIZE-5;
                    width = (int)(width * ratio);
                }
                else {
                    ratio = (double)getHeight() / height;
                    height = getHeight();
                    width = (int)(width * ratio);
                }
            }

            image = image.getScaledInstance(width, height, java.awt.Image.SCALE_DEFAULT);
        }

        /**
         * Implémentation : permet de redessiner le panel accueillant les images importées
         * @param g type Graphic
         */
        public void paintComponent(Graphics g) {
            g.setColor(bg);

            /*
             * If we don't do this, we will end up with garbage from previous
             * images if they have larger sizes than the one we are currently
             * drawing. Also, it seems that the file list can paint outside
             * of its rectangle, and will cause odd behavior if we don't clear
             * or fill the rectangle for the accessory before drawing. This might
             * be a bug in JFileChooser.
             */
            g.fillRect(0, 0, ACCSIZE, getHeight());
            g.drawImage(image, getWidth() / 2 - width / 2 + 5,
                    getHeight() / 2 - height / 2, this);
        }

    }
}
